// BehaviorCollector.ts - 用户行为采集器
// @/utils/monitor/collectors/BehaviorCollector.ts

import { MonitorEventBus } from '../core/MonitorEventBus';
import { MonitorConfig, EventType, BehaviorEventData, ICollector } from '../MonitorTypes';

/**
 * 用户行为采集器
 * 采集页面访问、用户交互、路由变化等行为数据
 */
export class BehaviorCollector implements ICollector {
  public readonly name = 'BehaviorCollector';
  
  private eventBus: MonitorEventBus;
  private config: MonitorConfig;
  private isStarted: boolean = false;
  private cleanup: Array<() => void> = [];
  
  // 节流配置
  private clickThrottle: number = 500; // 点击事件节流时间
  private lastClickTime: number = 0;
  private scrollThrottle: number = 1000; // 滚动事件节流时间
  private lastScrollTime: number = 0;
  
  // 页面统计
  private pageStartTime: number = Date.now();
  private mouseMovements: Array<{ x: number; y: number; t: number }> = [];
  
  // 定时器
  private timers: Set<any> = new Set();

  constructor(eventBus: MonitorEventBus, config: MonitorConfig) {
    this.eventBus = eventBus;
    this.config = config;
  }

  /**
   * 初始化采集器
   */
  public init(config: MonitorConfig): void {
    this.config = config;
  }

  /**
   * 启动用户行为采集
   */
  public start(): void {
    if (this.isStarted) {
      return;
    }

    this.trackPageView();
    this.trackClicks();
    this.trackInputChanges();
    this.trackPageVisibility();
    this.trackPageUnload();
    this.trackScroll();
    this.trackMouseMovement();
    this.trackMiniProgramBehavior();
    
    this.isStarted = true;

    if (this.config.enableDebug) {
      console.log('[BehaviorCollector] Started behavior tracking');
    }
  }

  /**
   * 停止用户行为采集
   */
  public stop(): void {
    if (!this.isStarted) {
      return;
    }

    // 清理所有事件监听器
    this.cleanup.forEach(fn => fn());
    this.cleanup = [];
    
    // 清理所有定时器
    this.timers.forEach(timer => clearTimeout(timer));
    this.timers.clear();
    
    this.isStarted = false;

    if (this.config.enableDebug) {
      console.log('[BehaviorCollector] Stopped behavior tracking');
    }
  }

  /**
   * 销毁采集器
   */
  public destroy(): void {
    this.stop();
    this.mouseMovements = [];
  }

  /**
   * 追踪页面访问
   */
  private trackPageView(): void {
    // #ifdef H5
    if (typeof window !== 'undefined') {
      const behaviorData: BehaviorEventData = {
        action: 'pageview',
        target: 'page',
        url: window.location.href,
        title: document.title,
        referrer: document.referrer
      };

      this.emitBehavior(behaviorData);

      // 监听路由变化（支持 SPA）
      this.trackRouteChanges();
    }
    // #endif
  }

  /**
   * 追踪路由变化
   */
  private trackRouteChanges(): void {
    // #ifdef H5
    if (typeof window === 'undefined' || typeof history === 'undefined') {
      return;
    }

    // 监听 pushState 和 replaceState
    const originalPushState = history.pushState;
    const originalReplaceState = history.replaceState;
    const self = this;

    history.pushState = function(...args) {
      originalPushState.apply(history, args);
      self.handleRouteChange();
    };

    history.replaceState = function(...args) {
      originalReplaceState.apply(history, args);
      self.handleRouteChange();
    };

    // 监听 popstate 事件
    const popstateHandler = () => {
      this.handleRouteChange();
    };

    window.addEventListener('popstate', popstateHandler);

    this.cleanup.push(() => {
      history.pushState = originalPushState;
      history.replaceState = originalReplaceState;
      window.removeEventListener('popstate', popstateHandler);
    });
    // #endif
  }

  /**
   * 处理路由变化
   */
  private handleRouteChange(): void {
    // #ifdef H5
    if (typeof window === 'undefined') return;

    const behaviorData: BehaviorEventData = {
      action: 'route-change',
      target: 'page',
      url: window.location.href,
      title: document.title,
      referrer: document.referrer
    };

    this.emitBehavior(behaviorData);
    // #endif
  }

  /**
   * 追踪点击事件
   */
  private trackClicks(): void {
    // #ifdef H5
    if (typeof document === 'undefined') {
      return;
    }

    const clickHandler = (event: MouseEvent) => {
      const now = Date.now();
      
      // 节流处理
      if (now - this.lastClickTime < this.clickThrottle) {
        return;
      }
      
      this.lastClickTime = now;
      
      const target = event.target as HTMLElement;
      if (!target) return;

      const behaviorData: BehaviorEventData = {
        action: 'click',
        target: target.tagName.toLowerCase(),
        targetInfo: {
          tagName: target.tagName,
          className: target.className,
          id: target.id,
          text: this.getElementText(target),
          xpath: this.getXPath(target)
        },
        coordinates: {
          x: event.clientX,
          y: event.clientY,
          pageX: event.pageX,
          pageY: event.pageY
        }
      };

      this.emitBehavior(behaviorData);
    };

    document.addEventListener('click', clickHandler, true);
    
    this.cleanup.push(() => {
      document.removeEventListener('click', clickHandler, true);
    });
    // #endif
  }

  /**
   * 追踪输入变化
   */
  private trackInputChanges(): void {
    // #ifdef H5
    if (typeof document === 'undefined') {
      return;
    }

    const inputHandler = (event: Event) => {
      const target = event.target as HTMLInputElement;
      if (!target) return;
      
      // 不记录敏感信息
      if (target.type === 'password' || 
          target.getAttribute('data-sensitive') === 'true') {
        return;
      }
      
      // 防抖处理
      const timer = setTimeout(() => {
        const behaviorData: BehaviorEventData = {
          action: 'input',
          target: target.tagName.toLowerCase(),
          targetInfo: {
            tagName: target.tagName,
            type: target.type,
            name: target.name,
            id: target.id,
            className: target.className,
            xpath: this.getXPath(target)
          },
          value: target.value.length // 只记录长度，不记录具体内容
        };

        this.emitBehavior(behaviorData);
        this.timers.delete(timer);
      }, 500);
      
      this.timers.add(timer);
    };

    document.addEventListener('input', inputHandler, true);
    
    this.cleanup.push(() => {
      document.removeEventListener('input', inputHandler, true);
    });
    // #endif
  }

  /**
   * 追踪页面可见性变化
   */
  private trackPageVisibility(): void {
    // #ifdef H5
    if (typeof document === 'undefined') {
      return;
    }

    let hiddenTime: number = 0;
    
    const visibilityHandler = () => {
      if (document.hidden) {
        hiddenTime = Date.now();
      } else if (hiddenTime) {
        const behaviorData: BehaviorEventData = {
          action: 'visibility-change',
          target: 'page',
          visible: true,
          duration: Date.now() - hiddenTime
        };

        this.emitBehavior(behaviorData);
        hiddenTime = 0;
      }
    };

    document.addEventListener('visibilitychange', visibilityHandler);
    
    this.cleanup.push(() => {
      document.removeEventListener('visibilitychange', visibilityHandler);
    });
    // #endif
  }

  /**
   * 追踪页面卸载
   */
  private trackPageUnload(): void {
    // #ifdef H5
    if (typeof window === 'undefined') {
      return;
    }

    const unloadHandler = () => {
      const behaviorData: BehaviorEventData = {
        action: 'page-unload',
        target: 'page',
        duration: Date.now() - this.pageStartTime
      };

      // 使用同步方式确保数据发送
      this.emitBehavior(behaviorData, true);
    };

    window.addEventListener('beforeunload', unloadHandler);
    
    this.cleanup.push(() => {
      window.removeEventListener('beforeunload', unloadHandler);
    });
    // #endif
  }

  /**
   * 追踪滚动行为
   */
  private trackScroll(): void {
    // #ifdef H5
    if (typeof window === 'undefined') {
      return;
    }

    let maxScroll = 0;
    
    const scrollHandler = () => {
      const now = Date.now();
      
      // 节流处理
      if (now - this.lastScrollTime < this.scrollThrottle) {
        return;
      }
      
      this.lastScrollTime = now;
      
      const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
      const scrollHeight = document.documentElement.scrollHeight;
      const clientHeight = document.documentElement.clientHeight;
      const scrollPercentage = scrollHeight > clientHeight 
        ? (scrollTop / (scrollHeight - clientHeight)) * 100 
        : 0;
      
      maxScroll = Math.max(maxScroll, scrollPercentage);
      
      const behaviorData: BehaviorEventData = {
        action: 'scroll',
        target: 'page',
        scrollTop: scrollTop,
        scrollPercentage: Math.round(scrollPercentage),
        maxScrollPercentage: Math.round(maxScroll)
      };

      this.emitBehavior(behaviorData);
    };

    window.addEventListener('scroll', scrollHandler, { passive: true });
    
    this.cleanup.push(() => {
      window.removeEventListener('scroll', scrollHandler);
    });
    // #endif
  }

  /**
   * 追踪鼠标移动（简化版热力图）
   */
  private trackMouseMovement(): void {
    // #ifdef H5
    if (typeof document === 'undefined') {
      return;
    }

    let moveTimer: any = null;
    
    const mouseMoveHandler = (event: MouseEvent) => {
      this.mouseMovements.push({
        x: event.clientX,
        y: event.clientY,
        t: Date.now()
      });
      
      // 限制数组大小
      if (this.mouseMovements.length > 100) {
        this.mouseMovements.shift();
      }
      
      // 防抖处理，每2秒计算一次热力图数据
      if (moveTimer) {
        clearTimeout(moveTimer);
        this.timers.delete(moveTimer);
      }
      
      moveTimer = setTimeout(() => {
        if (this.mouseMovements.length > 10) {
          const behaviorData: BehaviorEventData = {
            action: 'mouse-activity',
            target: 'page',
            movements: this.mouseMovements.slice(-10) // 只发送最近10个点
          };

          this.emitBehavior(behaviorData);
        }
        this.timers.delete(moveTimer);
      }, 2000);
      
      this.timers.add(moveTimer);
    };

    document.addEventListener('mousemove', mouseMoveHandler, { passive: true });
    
    this.cleanup.push(() => {
      document.removeEventListener('mousemove', mouseMoveHandler);
      if (moveTimer) {
        clearTimeout(moveTimer);
      }
    });
    // #endif
  }

  /**
   * 追踪小程序行为
   */
  private trackMiniProgramBehavior(): void {
    // #ifdef MP
    if (typeof uni === 'undefined') {
      return;
    }

    try {
      // 追踪小程序生命周期
      const pages = getCurrentPages();
      if (pages.length > 0) {
        const currentPage = pages[pages.length - 1];
        
        const behaviorData: BehaviorEventData = {
          action: 'miniprogram-pageview',
          target: 'page',
          route: currentPage.route,
          options: currentPage.options
        };

        this.emitBehavior(behaviorData);
      }

      // 监听小程序隐藏和显示
      const hideHandler = () => {
        this.emitBehavior({
          action: 'miniprogram-hide',
          target: 'app'
        });
      };

      const showHandler = () => {
        this.emitBehavior({
          action: 'miniprogram-show',
          target: 'app'
        });
      };

      uni.onAppHide(hideHandler);
      uni.onAppShow(showHandler);

    } catch (error) {
      if (this.config.enableDebug) {
        console.warn('[BehaviorCollector] Miniprogram behavior tracking failed:', error);
      }
    }
    // #endif
  }

  /**
   * 获取元素文本
   */
  private getElementText(element: HTMLElement): string {
    try {
      const text = element.innerText || element.textContent || '';
      return text.trim().substring(0, 100); // 限制长度
    } catch (error) {
      return '';
    }
  }

  /**
   * 获取元素XPath
   */
  private getXPath(element: HTMLElement): string {
    try {
      if (element.id) {
        return `//*[@id="${element.id}"]`;
      }
      
      const paths: string[] = [];
      let currentElement: HTMLElement | null = element;
      
      while (currentElement && currentElement.nodeType === Node.ELEMENT_NODE) {
        let index = 0;
        let sibling = currentElement.previousSibling;
        
        while (sibling) {
          if (sibling.nodeType === Node.ELEMENT_NODE && 
              sibling.nodeName === currentElement.nodeName) {
            index++;
          }
          sibling = sibling.previousSibling;
        }
        
        const tagName = currentElement.nodeName.toLowerCase();
        const pathIndex = index ? `[${index + 1}]` : '';
        paths.unshift(`${tagName}${pathIndex}`);
        
        currentElement = currentElement.parentElement;
      }
      
      return paths.length ? `/${paths.join('/')}` : '';
    } catch (error) {
      return '';
    }
  }

  /**
   * 发送行为事件
   */
  private emitBehavior(behaviorData: BehaviorEventData, urgent: boolean = false): void {
    this.eventBus.emit(EventType.BEHAVIOR, {
      type: EventType.BEHAVIOR,
      data: behaviorData,
      timestamp: Date.now()
    });

    if (this.config.enableDebug) {
      console.log('[BehaviorCollector] Behavior captured:', behaviorData);
    }
  }

  /**
   * 获取采集器状态信息
   */
  public getStatus(): { isStarted: boolean; timersCount: number; movementsCount: number; name: string } {
    return {
      name: this.name,
      isStarted: this.isStarted,
      timersCount: this.timers.size,
      movementsCount: this.mouseMovements.length
    };
  }
} 